
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.sun.org.apache.xalan.internal.xsltc.compiler.Import;
import org.codehaus.groovy.grails.commons.ApplicationAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils
import org.codehaus.groovy.grails.web.context.ServletContextHolder
import org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib


import ar.com.photo_admin.domain.*;
import ar.com.photo_admin.domain.order_state.FinalizedOrderState
import ar.com.photo_admin.domain.price_strategies.*;
import ar.com.photo_admin.service.*;
import ar.com.photo_admin.service.marshallers.*;

class BootStrap {
	
	//Real de tbruno88@gm
	def fotografo1ClientId = 8725963455797102
	def fotografo1ClientSecret = "LJG6lOko0InUnySG4bfIQ4f6KkSaYbQI"
	// Notif url : http://190.189.200.7/MPNotification/notification?photographerId=1 
	
	/* TestUser
	def fotografo1ClientId = 623938634179880
	def fotografo1ClientSecret = "GkqeeLS8xpoqaRXps0q2HpEzZ5loxf6X"
	*/
	
	def fotografo2ClientId = 6467682526503201
	def fotografo2ClientSecret = "Pno5Jj1ep6uskI1wxBfFHK82DRQmhAmT"
	
	def eventService
	def eventPhotoService
	def purchaseOrderService	
	
	def servletContext
	ApplicationContext ctx
	def grailsApplication
		
	String SERVER_PATH = "images/upload";
	String SERVER_BOOTSTRAP_PATH = "web-app/images/bootstrap-images"
	String SERVER_LOAD_ALBUMS_PATH;	
	
	boolean LOAD_FULL_DATA; 
	
    def init = { servletContext ->								
		ctx = servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT);
			
		registerMarshallers();
		initConstants();
		
		environments {

			development {
							
				def users = User.list()
				if (users.size() == 0){													
					def priceStrat = new PriceStrategyDiscountOverAmountPhotos(amountCopies:10,discount:10);
					def priceStrat2 = new PriceStrategyDiscountOverAmountPrice(amountPrice:10,discount:10);
					def priceStrat3 = new PriceStrategyDiscountOverAmountPrice(amountPrice:10,discount:10);
					
					User fotografo = addPhotographer("info@pedrobruno.com","fotografo","Pedro","Bruno","zarasa1",priceStrat2,true,fotografo1ClientId,fotografo1ClientSecret,"1556534545")
					User fotografo2 = addPhotographer("tpfiuba2013@gmail.com","fotografo2","nombree","apellidoo","zarasa1",priceStrat,true,fotografo2ClientId,fotografo2ClientSecret,"1556534545")			
					User user = addUser("nicolasgnr@gmail.com","nicolasgnr","nombre","apellido","12345678")				
					User cliente = addUser("tbruno88@gmail.com","cliente","nombre","apellido","zarasa1")
					User cliente2 = addUser("tbruno89@gmail.com","cliente2","nombre","apellido","zarasa1")
					User usuario1 = addUser("tbruno3@gmail.com","usuario1","nombre","apellido","zarasa1")
					User usuario2 = addUser("tbruno4@gmail.com","usuario2","nombre","apellido","zarasa1")
					User admin = addPhotographer("admin@gmail.com","admin","administrador","administrador","admin",priceStrat3,true,fotografo1ClientId,fotografo1ClientSecret,"1556534545")
										
					def userRole = new Role(authority: 'ROLE_USER').save(flush: true)				
					def fotografoRole = new Role(authority: 'ROLE_PHOTOGRAPHER').save(flush: true)				
					def clienteRole = new Role(authority: 'ROLE_CLIENT').save(flush: true)								
					def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true)
					
					UserRole.create(user, userRole, true)
					UserRole.create(admin, adminRole, true)
					UserRole.create(fotografo, fotografoRole, true)
					UserRole.create(fotografo2, fotografoRole, true)
					UserRole.create(cliente, clienteRole, true)
					UserRole.create(cliente2, clienteRole, true)
					UserRole.create(usuario1, userRole, true)
					UserRole.create(usuario2, userRole, true)
					
					addInitialData(fotografo, cliente2);
																	
					/*		
					//Creo un evento que contenga las imagenes				
					Calendar cal = Calendar.instance
					cal.add(Calendar.MONTH, -6)				
					
					def eventNumber = DomainObject.list().size()+1				
					Event event1 = new Event(number:eventNumber,name: "Evento autogenerado", description:"Aliquam dignissim elementum est sit amet iaculis. Integer pretium ultricies risus, condimentum molestie odio", eventDate: cal.getTime(), photographer:fotografo, client: cliente);		
					def anAlbum = new EventAlbum(name:"AlbumAutogenerado1", description:"Aliquam dignissim elementum est sit amet iaculis. Integer pretium ultricies risus, condimentum molestie odio euismod vitae.", event:event1);
					def anotherAlbum = new EventAlbum(name:"AlbumAutogenerado2", description:"",event:event1);
					
					event1.addToAlbums(anAlbum);
					event1.addToAlbums(anotherAlbum);
					
					//Guarda los albums
					event1 = event1.save(flush:true,failOnError: true);
					
					def anEventPhoto = null;
					
					int numberOfPhotos = 0 ;
					
					def eventPath = getImagesRootPath()+File.separator+eventNumber+File.separator+"local";
					new File(eventPath).mkdirs();
									
					new File(SERVER_BOOTSTRAP_PATH).eachFile { file ->
						
						if (file.name.endsWith(".jpg") || file.name.endsWith(".png")){
							anEventPhoto = eventPhotoService.createPhotoTemporally(event1.id,file.getBytes(),file.name)
							
							// Le agrego todas las fotos
							anAlbum.addToAlbumPhotos(anEventPhoto)
							//.save(flush:true);
							anAlbum.save(flush:true);
							
							if(numberOfPhotos == 1){
								//Hago cover a la foto!
								anAlbum.setCoverPhoto(anEventPhoto)
								anAlbum.save(flush:true);
								event1.setCoverPhoto(anEventPhoto);
							}
							
							// Al album 2 le agrego la mitado de las fotos
							if(numberOfPhotos % 2 == 0 ){
								anotherAlbum.addToAlbumPhotos(anEventPhoto)
								anotherAlbum.save(flush:true);
								if(numberOfPhotos == 2){
									//Hago cover a la foto!
									anotherAlbum.setCoverPhoto(anEventPhoto)
									anotherAlbum.save(flush:true);
								}
							}
							
							numberOfPhotos++;
						}
									
					}
					eventService.confirmChangesEvent(event1);				
					event1.published = false;
					event1 = event1.save(flush:true,failOnError: true);
											
					 
					Set albums = [anAlbum]				
								
					EventAlbumToken token = new EventAlbumToken(token: "token1", albums: albums)
					token.save(flush:true, failOnError:true)
					
					createShoppingCart(cliente,anotherAlbum);
					
					
					anAlbum.addToUserAlbumAccesses(usuario1)
					anotherAlbum.addToUserAlbumAccesses(usuario2)
					*/				
					
					createPhotosAvailableProperties();
										
					createStartingPrices(fotografo)
					createStartingPrices(fotografo2)								
					
					addPresentationUrls(fotografo);
					
					/*
					 * Messages
					 */
					(0..4).each {
						createMessage("Subject" + it + "-Fotografo", "Message" + it + "-Fotografo", fotografo, usuario1)
					}
					
					markUserNotificationsAsRead(fotografo)
					
					
//					(0..25).each {
//						createMessage("Subject" + it + "-Usuario1", "Message" + it + "-Usuario1", usuario1, fotografo)
//					}
				}
			}
			test {
				productionAndTestingContent()
			}			
			production {
				productionAndTestingContent()							
			}
		}
			
		
    }
	
    def destroy = {
		
    }
	
	
	def productionAndTestingContent(){
		
		def fotografo2ProdClientId = 4958101768876894
		def fotografo2ProdClientSecret = "xB2TZexe5FYdslLTj818W1hDdSWpAqDS"
		
		log.info "Comenzando la ejecucion de datos"
		//Refactor
		//Primer deploy?
		def users = User.list()
		if (users.size() == 0){
			def priceStrat = new PriceStrategyDiscountOverAmountPhotos(amountCopies:10,discount:10);
			def priceStrat2 = new PriceStrategyDiscountOverAmountPrice(amountPrice:10,discount:10);
			def priceStrat3 = new PriceStrategyDiscountOverAmountPrice(amountPrice:10,discount:10);
					
			User fotografo = addPhotographer("info@pedrobruno.com","fotografo","Pedro","Bruno","zarasa1",priceStrat2,true,fotografo1ClientId,fotografo1ClientSecret,"1556534545")
			User fotografo2 = addPhotographer("tomas.bruno.o2@gmail.com","fotografo2","nombree","apellidoo","zarasa1",priceStrat,true,fotografo2ProdClientId,fotografo2ProdClientSecret,"1556534545")
			User user = addUser("nicolasgnr@gmail.com","nicolasgnr","nombre","apellido","12345678")
			User cliente = addUser("tpfiuba2013@gmail.com","cliente","nombre","apellido","zarasa1")
			User cliente2 = addUser("tbruno89@gmail.com","cliente2","nombre","apellido","zarasa1")
			User usuario1 = addUser("tbruno3@gmail.com","usuario1","nombre","apellido","zarasa1")
			User usuario2 = addUser("tbruno4@gmail.com","usuario2","nombre","apellido","zarasa1")
			User admin = addPhotographer("admin@gmail.com","admin","administrador","administrador","admin",priceStrat3,true,fotografo1ClientId,fotografo1ClientSecret,"1556534545")
	
			def userRole = new Role(authority: 'ROLE_USER').save(flush: true)
			def fotografoRole = new Role(authority: 'ROLE_PHOTOGRAPHER').save(flush: true)
			def clienteRole = new Role(authority: 'ROLE_CLIENT').save(flush: true)
			def adminRole = new Role(authority: 'ROLE_ADMIN').save(flush: true)
			
			UserRole.create(user, userRole, true)
			UserRole.create(admin, adminRole, true)
			UserRole.create(fotografo, fotografoRole, true)
			UserRole.create(fotografo2, fotografoRole, true)
			UserRole.create(cliente, clienteRole, true)
			UserRole.create(usuario1, userRole, true)
			UserRole.create(usuario2, userRole, true)
							
			addInitialData(fotografo, cliente2);
			
			createPhotosAvailableProperties();
			
			createStartingPrices(fotografo)
			createStartingPrices(fotografo2)
			
			addPresentationUrls(fotografo);
		}
	}
	
	
	def markUserNotificationsAsRead(User user){
		user.userNotifications.each {
			it.notified = true
			it.save(flush:true)
		}
	}
	
	def createShoppingCart(User user, EventAlbum album){
		ShoppingCart cart = new ShoppingCart(user : user)
		
		//Agrego todas las fotos del album al carrito.
		album.getAlbumPhotos().each {
			cart.addToItems(new ShoppingCartItem(photo:it));
			
		}
		cart.save();
	}
	
	def getImagesRootPath(){
		return ctx.getResource(SERVER_PATH).getFile().toString() + File.separatorChar;
	}
	
	def getBootstrapImagesRootPath(){
		return ctx.getResource(SERVER_BOOTSTRAP_PATH).getFile().toString() + File.separatorChar;
	}	
	
	def createPhotosAvailableProperties(){
		// Genero algunos tamaños de fotos por defecto
		new Size(height:10,width:15).save(flush:true);
		new Size(height:13,width:18).save(flush:true);
		new Size(height:15,width:20).save(flush:true);
		new Size(height:20,width:30).save(flush:true);
		
		//Genero los dos tipos de papertypes
		new PaperType(i18nDescription:"paper.type.matte").save(flush:true);
		new PaperType(i18nDescription:"paper.type.glossy").save(flush:true);
		
		//Genero los bordes
		new PaperBorder(i18nDescription:"paper.border.with",border:0).save(flush:true);
		new PaperBorder(i18nDescription:"paper.border.without",border:1).save(flush:true);	
	}
	
	def createStartingPrices(user){
		def price10x15 = new PhotoPrice(size: Size.findByHeightAndWidth(10,15), price:10)
		def price13x18 = new PhotoPrice(size: Size.findByHeightAndWidth(13,18), price:12)
		def price15x20 = new PhotoPrice(size: Size.findByHeightAndWidth(15,20), price:14)
		def price20x30 = new PhotoPrice(size: Size.findByHeightAndWidth(20,30), price:16)
		def photographerPrices = new PhotographerPrices(photographer:user, validSince:new Date());
		photographerPrices.addToPrices(price10x15).addToPrices(price13x18).addToPrices(price15x20).addToPrices(price20x30).save(flush:true);
		
		
	} 
	
	
	def createPurchaseOrders(fotografo,cliente){
		for (int i = 0 ; i<30 ;i++){
			PurchaseOrder order = new PurchaseOrder(photographer:fotografo,client:cliente,price:10,orderItems:[],amountCopies:i, MPstatus: MPOrderStatus.CANCELLED)
			order.save(flush:true, failOnError:true)
		}				
	}	
	
	def addRandomNotifications(user,user2){
		for (int i = 0 ; i<10 ;i++){
			def number = Notification.list().size()
			Notification notif = new Notification(description:"Esta es la notificacion ${number}", associatedUrl:"no tiene todavia");			
			notif.save(flush:true, failOnError:true)
			notif.addToUserNotifications(user)
			notif.addToUserNotifications(user2)			
		}
	}
	
	def addPresentationUrls(user){
		def presentationUrls = []			
		
		presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/355_38442881606_921_n.jpg")
		presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/420173_10150497937841607_1866096784_n.jpg")
		presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/548576_391929270871527_1463531619_n.jpg")
		//presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/26925_369195786606_458226_n.jpg")
		presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/57969_429389866606_2447895_n.jpg")
		presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/225849_10150193849156607_7181807_n.jpg")
		presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/555262_10151195740116607_1166169596_n.jpg")
		presentationUrls.add("http://commondatastorage.googleapis.com/photo-admin-app/PresentationPhotos/734858_10151167501521607_1178926001_n.jpg")		
		
		presentationUrls.each { url ->
			PresentationPhoto photo = new PresentationPhoto(url: url)
			user.addToPresentationPhotos(photo)
		}
		

		user.save(flush:true, failOnError:true)
	}
	
	def addUser(email,username,name,lastname,password){
		User user = new User(email: email, username: username, name: name, lastname: lastname, password: password)
		//addNotifications(user);
		user.save(flush:true)
		return user
	}
	
	def addPhotographer(email,username,name,lastname,password,priceStrategy,paymentOnlineEnabled,clientId,clientSecret,phone){
		def fotografo = new Photographer(email: email, username: username, name: name, lastname: lastname, password: password, priceStrategy: priceStrategy, paymentOnlineEnabled: paymentOnlineEnabled, clientId: clientId, clientSecret:clientSecret, telephone: phone)				
		fotografo.name = name
		fotografo.lastname = lastname
		priceStrategy.photographer = fotografo;
		fotografo.save(flush:true, failOnError:true)
		return fotografo;
	}
	
	def registerMarshallers(){
		new EventMarshaller().register()
		new AlbumMarshaller().register()
		new PhotoMarshaller().register()
		new AlbumListMarshaller().register()
	}

	def addPhotosInDirectoryToEvent(event,directory){
		def photo = null;									
		def eventPath = getImagesRootPath()+File.separator+event.number+File.separator+"local";
		new File(eventPath).mkdirs();
						
		new File(directory).eachFile { file ->
			
			if (file.name.endsWith(".jpg") || file.name.endsWith(".png")){				
				photo = eventPhotoService.createPhotoTemporally(event.id,file.getBytes(),file.name)															
				if(file.getName()=="cover.jpg"){
					event.setCoverPhoto(photo);
					event = event.save(flush:true);
				}								
			}
						
		}
		eventService.confirmChangesEvent(event);
		event.published = false;
		event = event.save(flush:true,failOnError: true);
	}
	
	def addEventPhotosToAlbum(Event event,album){
		event.photos.each { photo ->
			album.addToAlbumPhotos(photo)
			album.save(flush:true);
			
			if(photo.name == "cover.jpg"){
				//Hago cover a la foto!
				album.setCoverPhoto(photo)
				album.save(flush:true);			
			}
		}
	}
	
	def initConstants(){
		LOAD_FULL_DATA = grailsApplication.config.init.data.load
		SERVER_LOAD_ALBUMS_PATH = grailsApplication.config.init.photos.dir		
	}
	
	def addInitialData(fotografo, cliente2) {
		Calendar cal
		
		if (LOAD_FULL_DATA){

			Random random = new Random()
								
			// Creo los eventos que existen en la carpeta.
			new File(SERVER_LOAD_ALBUMS_PATH).eachFile() { file ->

				cal = Calendar.instance
				cal.add(Calendar.MONTH, -1 * random.nextInt(6))
				Date randomDate = cal.getTime()
				
				//Creo el evento y un album que contendra todas las fotos.
				def eventName = file.getName()
				
				log.info "Creando el evento ${eventName} . Fecha de creacion: ${randomDate}"
				def anEventNumber = DomainObject.list().size()+1
				Event anEvent = new Event(number:anEventNumber,name: eventName , eventDate: randomDate, photographer:fotografo, client: cliente2);
				anEvent = anEvent.save(flush:true,failOnError: true);
				addPhotosInDirectoryToEvent(anEvent,SERVER_LOAD_ALBUMS_PATH+File.separator+eventName)
				anEvent = anEvent.save(flush:true,failOnError: true);
				
				//Creo entre 1 y 3 albums por evento.
				def amountAlbums = 1 + random.nextInt(3)				
				for (int i=0 ; i < amountAlbums; i++) {
					def album = new EventAlbum(name:eventName+" "+i,  event:anEvent);
					anEvent.addToAlbums(album);
					anEvent = anEvent.save(flush:true,failOnError: true);
					
					addEventPhotosToAlbum(anEvent,album);
				}
				
				
			}
			
			// Creo ordenes de compra asociadas a los eventos
			cal = Calendar.instance
			
			def monthsOffset = -6
			cal.add(Calendar.MONTH,  monthsOffset)
			for (int i = 0 ; i <6 ; i++){
				Date intervalEnd = cal.getTime()
				cal.add(Calendar.MONTH, 1)
				Date intervalBeginning = cal.getTime()
				
				def amountOrders = 2 + random.nextInt(6)
				for (int j = 0 ; j < amountOrders ; j++) {
					PurchaseOrder order = random.nextBoolean() ?
						 new PurchaseOrder(photographer:fotografo,client:cliente2,price:200+random.nextInt(300),orderItems:[],amountCopies:j, paidOnline:false, dateCreated:intervalBeginning ) :
						new PurchaseOrder(photographer:fotografo,client:cliente2,price:200+random.nextInt(300),orderItems:[],amountCopies:j, paidOnline:true, MPstatus: MPOrderStatus.APPROVED, dateCreated:intervalBeginning )						
					order.save(flush:true, failOnError:true)
														
					order.dateCreated = intervalBeginning
					purchaseOrderService.completeConfirmation(order)
					order.finish()
					order.save(flush:true, failOnError:true)
				}							
			}
		}	
	}
	
	def createMessage(String subject, String body, User to, User from, notified = false) {
		Message message = new Message(subject : subject, message : body)
		UserMessage userMessage = new UserMessage(message : message, notified : notified)

		from.addToSentMessages(message)
		to.addToReceivedMessages(userMessage)
		
		to.save(flush:true)
		from.save(flush:true)
	}
}
